﻿using FrameworkCore.DI;
using NodaTime;
using NodaTime.Serialization.SystemTextJson;
using Polly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

#nullable disable

namespace AiBLSmartEdu.Module.AIHealthManage.API.Services;

public class OllamaService : IScopedDependency
{
    private readonly HttpClient _httpClient;
    private readonly JsonSerializerOptions _jsonOptions;
    private const string BaseUrl = "http://localhost:11434";

    public OllamaService(HttpClient httpClient)
    {
        _httpClient = httpClient;
        _httpClient.BaseAddress = new Uri(BaseUrl);

        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            WriteIndented = true
        };
        _jsonOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
    }

    public async Task<OllamaResponse> GenerateHealthAnalysis2(string healthDataJson)
    {
        // 构建医学分析提示模板
        string prompt = $$"""
        [角色]
        你是一名资深内分泌科医生，需要对患者的健康数据进行全面分析并生成医学报告。
        
        [任务]
        基于以下结构化的健康数据：
        {{healthDataJson}}
        
        请进行：
        1. 关键指标分析（血糖、血压、BMI等）
        2. 糖尿病风险评估（使用FINDRISC评分）
        3. 心血管风险评估（使用WHO/ISH风险评估图）
        4. 生成具体改善建议
        5. 推荐监测频率
        
        [输出要求]
        - 使用JSON格式
        - 包含risk_assessment, recommendations, follow_up_plan三个主部分
        - 语言：中文
        - 符合中国临床指南标准
        """;

        var requestBody = new OllamaRequest
        {
            Model = "deepseek-r1", // 医疗专用模型
            Prompt = prompt,
            Stream = false,
            Options = new ModelOptions
            {
                Temperature = 0.3,      // 低随机性保证专业准确性
                RepeatLastN = 64,
                RepeatPenalty = 1.15,
                NumCtx = 4096,          // 足够处理完整报告
                TopK = 20,
                TopP = 0.9
            }
        };

        var jsonContent = JsonSerializer.Serialize(requestBody, _jsonOptions);
        var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

        // 使用Polly添加重试机制
        var retryPolicy = Policy
            .Handle<HttpRequestException>()
            .OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
            .WaitAndRetryAsync(3, retryAttempt =>
                TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

        var response = await retryPolicy.ExecuteAsync(async () =>
            await _httpClient.PostAsync("/api/generate", content));

        response.EnsureSuccessStatusCode();

        var responseBody = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<OllamaResponse>(responseBody, _jsonOptions);
    }

    public async Task<string> GenerateHealthAnalysis(string healthDataJson)
    {
        // 验证输入数据是否为空或无效
        if (string.IsNullOrWhiteSpace(healthDataJson) || !IsValidJson(healthDataJson))
        {
            throw new ArgumentException("Invalid or empty health data JSON", nameof(healthDataJson));
        }

        // 构建医学分析提示模板
        string prompt = $$"""
    [角色]
    你是一名资深内分泌科医生，需要对患者的健康数据进行全面分析，并生成一份简洁易读的诊断报告。

    [任务]
    基于以下结构化的健康数据：
    {{healthDataJson}}

    请进行：
    1. 关键指标分析（血糖、血压、BMI等）
    2. 糖尿病风险评估（使用FINDRISC评分）
    3. 心血管风险评估（使用WHO/ISH风险评估图）
    4. 提供具体改善建议
    5. 推荐监测频率

    [输出要求]
    - 输出一份简洁易读的诊断报告
    - 包含以下内容：
      - 患者基本信息（性别、年龄、BMI等）
      - 主要问题总结（糖尿病、高血压等）
      - 具体建议（饮食、运动、药物等）
      - 监测计划（血糖、血压等）
    - 语言：中文
    - 符合中国临床指南标准
    """;

        // 构建请求体
        var requestBody = new OllamaRequest
        {
            Model = "deepseek-r1", // 
            Prompt = prompt,
            Stream = false,
            Options = new ModelOptions
            {
                Temperature = 0.3,      // 低随机性保证专业准确性
                RepeatLastN = 64,
                RepeatPenalty = 1.15,
                NumCtx = 4096,          // 足够处理完整报告
                TopK = 20,
                TopP = 0.9
            }
        };

        // 序列化请求体
        var jsonContent = JsonSerializer.Serialize(requestBody, _jsonOptions);
        var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

        // 使用Polly添加重试机制
        var retryPolicy = Policy
            .Handle<HttpRequestException>()
            .OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
            .WaitAndRetryAsync(3, retryAttempt =>
                TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

        // 发送请求并获取响应
        var response = await retryPolicy.ExecuteAsync(async () =>
            await _httpClient.PostAsync("/api/generate", content));

        response.EnsureSuccessStatusCode();

        // 读取响应内容
        var responseBody = await response.Content.ReadAsStringAsync();
        var ollamaResponse = JsonSerializer.Deserialize<OllamaResponse>(responseBody, _jsonOptions);

        // 提取模型生成的诊断报告
        return ExtractDiagnosticReport(ollamaResponse.Response);
    }

    // 验证输入数据是否为有效JSON
    private bool IsValidJson(string json)
    {
        try
        {
            JsonDocument.Parse(json);
            return true;
        }
        catch
        {
            return false;
        }
    }

    // 从模型返回的自由文本中提取诊断报告
    private string ExtractDiagnosticReport(string rawResponse)
    {
        // 如果模型返回的内容已经是简洁诊断报告，则直接返回
        if (!rawResponse.Contains("[")) // 简单判断是否为自由文本
        {
            return rawResponse.Trim();
        }

        // 否则尝试提取关键信息
        var lines = rawResponse.Split(new[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

        // 构建诊断报告
        var report = new StringBuilder();
        foreach (var line in lines)
        {
            if (line.StartsWith("[") || string.IsNullOrWhiteSpace(line)) continue; // 跳过提示部分
            report.AppendLine(line.Trim());
        }

        return report.ToString().Trim();
    }
}

public class OllamaRequest
{
    [JsonPropertyName("model")]
    public string Model { get; set; } = "llama2";

    [JsonPropertyName("prompt")]
    public string Prompt { get; set; }

    [JsonPropertyName("stream")]
    public bool Stream { get; set; } = false;

    [JsonPropertyName("options")]
    public ModelOptions Options { get; set; } = new ModelOptions();
}

public class ModelOptions
{
    [JsonPropertyName("temperature")]
    public double Temperature { get; set; } = 0.8;

    [JsonPropertyName("repeat_last_n")]
    public int RepeatLastN { get; set; } = 64;

    [JsonPropertyName("repeat_penalty")]
    public double RepeatPenalty { get; set; } = 1.1;

    [JsonPropertyName("num_ctx")]
    public int NumCtx { get; set; } = 2048;

    [JsonPropertyName("top_k")]
    public int TopK { get; set; } = 40;

    [JsonPropertyName("top_p")]
    public double TopP { get; set; } = 0.9;
}

public class OllamaResponse
{
    [JsonPropertyName("model")]
    public string Model { get; set; }

    [JsonPropertyName("created_at")]
    public Instant CreatedAt { get; set; }

    [JsonPropertyName("response")]
    public string Response { get; set; }

    [JsonPropertyName("done")]
    public bool Done { get; set; }

    [JsonIgnore]
    public HealthAnalysisResult AnalysisResult =>
        TryParseJson(Response) ?? new HealthAnalysisResult();

    private HealthAnalysisResult? TryParseJson(string json)
    {
        try
        {
            return JsonSerializer.Deserialize<HealthAnalysisResult>(
                json,
                new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
        }
        catch
        {
            return null;
        }
    }
}

public class HealthAnalysisResult
{
    [JsonPropertyName("risk_assessment")]
    public RiskAssessment Risk { get; set; } = new RiskAssessment();

    [JsonPropertyName("recommendations")]
    public List<Recommendation> Recommendations { get; set; } = new List<Recommendation>();

    [JsonPropertyName("follow_up_plan")]
    public FollowUpPlan FollowUp { get; set; } = new FollowUpPlan();
}

public class RiskAssessment
{
    [JsonPropertyName("diabetes_risk")]
    public DiabetesRisk Diabetes { get; set; } = new DiabetesRisk();

    [JsonPropertyName("cardiovascular_risk")]
    public CardiovascularRisk Cardiovascular { get; set; } = new CardiovascularRisk();
}

public class DiabetesRisk
{
    [JsonPropertyName("score")]
    public double Score { get; set; }

    [JsonPropertyName("category")]
    public string Category { get; set; } = "低风险";
}

public class CardiovascularRisk
{
    [JsonPropertyName("score")]
    public double Score { get; set; }

    [JsonPropertyName("category")]
    public string Category { get; set; } = "低风险";
}

public class Recommendation
{
    [JsonPropertyName("category")]
    public string Category { get; set; } = "生活方式";

    [JsonPropertyName("action")]
    public string Action { get; set; } = "建议事项";

    [JsonPropertyName("priority")]
    public int Priority { get; set; } = 3; // 1-高, 2-中, 3-低
}

public class FollowUpPlan
{
    [JsonPropertyName("next_check_date")]
    public LocalDate? NextCheckDate { get; set; }

    [JsonPropertyName("monitoring_schedule")]
    public MonitoringSchedule Schedule { get; set; } = new MonitoringSchedule();
}

public class MonitoringSchedule
{
    [JsonPropertyName("glucose")]
    public List<string> GlucoseChecks { get; set; } = new List<string>();

    [JsonPropertyName("blood_pressure")]
    public List<string> BloodPressureChecks { get; set; } = new List<string>();
}
